﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Xml.Linq;
using WinForm_LogSystem;
using WinForm_ConfigSystem;
namespace XMLConstructor
{
    public partial class Form_XMLEditor : Form
    {
        #region 配置功能模块变量
        //默认配置
        XElement defaultConfig = new XElement("ConfigFile",
            new XElement("上次工作路径", Directory.GetCurrentDirectory()),
            new XElement("日志保存数", 10),
            new XElement("自动备份数量", 5),
            new XElement("自动备份间隔", 5)
            );
        ConfigSystem configSystem;
        string configFileName = "config.xml";
        #endregion 配置功能模块变量

        bool canDoNextStep = false;
        public XmlDialogState xmlDialogResult;

        //主xml
        XDocument xmlFile;
        //treeview和datagrid显示
        Dictionary<TreeNode, XElement> nodeToXml = new Dictionary<TreeNode, XElement>();

        //上次打开路径//////////////////////////////////可以优化为5个！
        string filePath = "";
        string fileName = "";
        string fileFullName = "";
        //现在选中的元素
        XElement currentElement;

        #region 保存功能模块变量
        //是否有*提示
        bool notSavedTips = false;
        string dataCellBeginEditValue;
        //为了显示是否保存
        string originallyFormName;
        //是否保存了xml文件
        bool isSaved = true;
        //是否打开了xml文件，或者是从一个xml文件开始
        bool isOpened = false;
        #endregion 保存功能模块变量

        #region 日志功能模块变量
        //日志系统变量
        LogSystem_RichTextBox logSystem_RichTextBox;
        //日志功能委托
        public WRITELOG WriteLog;
        #endregion 日志功能模块变量

        Random random = new Random();

        public Form_XMLEditor()
        {
            InitializeComponent();
        }

        #region Form其他函数
        //improve
        private void timer_AutoBackUp_Tick(object sender, EventArgs e)
        {
            //LogSystem.WriteLog(count++.ToString());
        }

        private void Form_XML_Load(object sender, EventArgs e)
        {
            //初始化日志系统
            logSystem_RichTextBox = new LogSystem_RichTextBox(this.richTextBox_Log);
            WriteLog += logSystem_RichTextBox.WriteLog;

            //初始化配置系统
            configSystem = new ConfigSystem(configFileName, defaultConfig);
            //增加事件：配置系统输出日志
            configSystem.OutputLog += logSystem_RichTextBox.WriteLog;
            configSystem.LoadConfigFile();

            //设置日志保存数
            logSystem_RichTextBox.saveCount = Convert.ToInt32(configSystem.configFile.Root.Element("日志保存数").Value);

            string originallyFormName = this.Text;

            openFileDialog_XML.Filter = "Xml files (*.xml)|*.xml";
            saveFileDialog_XML.Filter = "Xml files (*.xml)|*.xml";

            timer_AutoBackUp.Interval = Convert.ToInt32(configSystem.configFile.Root.Element("自动备份间隔").Value) * 60000;
        }
        //improve
        private void Form_XML_FormClosing(object sender, FormClosingEventArgs e)
        {
            configSystem.SaveConfigFile();
        }

        #endregion Form其他函数

        #region 系统生成函数区
        /// <summary>
        /// 加载xml到tree集合中
        /// </summary>
        /// <param name="x">元素</param>
        /// <param name="nodes">集合</param>
        void LoadXmlToTree(XElement x, TreeNodeCollection nodes)
        {
            TreeNode node = new TreeNode(x.Name.ToString());

            nodes.Add(node);
            nodeToXml.Add(node, x);
            if (x.HasElements)
            {
                foreach (var ele in x.Elements())
                {
                    LoadXmlToTree(ele, node.Nodes);
                }
            }
        }
        /// <summary>
        /// 判断下一步应该做什么
        /// </summary>
        /// <param name="nextStep">下一步设置</param>
        void XMLNextStep(XmlDialogState nextStep)
        {
            //初始化下一步结果
            xmlDialogResult = XmlDialogState.None;
            //调用其他窗口来获取下一步应该做什么
            Form_XMLNextStep form = new Form_XMLNextStep(this, nextStep);
            form.ShowDialog();

            switch (xmlDialogResult)
            {
                case XmlDialogState.Save: SaveXML(); if (canDoNextStep) ExecuteNextStep(nextStep); break;
                case XmlDialogState.SaveAs: SaveAsXML(); if (canDoNextStep) ExecuteNextStep(nextStep); break;
                case XmlDialogState.Open:
                case XmlDialogState.New:
                case XmlDialogState.Uninstall:
                case XmlDialogState.Exit: ExecuteNextStep(nextStep); break;
            }
        }
        /// <summary>
        /// 执行下一步
        /// </summary>
        /// <param name="nextStep">下一步指令</param>
        void ExecuteNextStep(XmlDialogState nextStep)
        {
            switch (nextStep)
            {
                case XmlDialogState.Open: OpenXML(); break;
                case XmlDialogState.New: NewXml(); break;
                case XmlDialogState.Uninstall: UninstallXml(); break;
                case XmlDialogState.Exit: ExitXml(); break;
            }
        }
        /// <summary>
        /// 设置保存的状态
        /// </summary>
        /// <param name="state">是否保存</param>
        private void SetIsSaved(bool state)
        {
            if (state == false)
            {
                //设置未保存
                isSaved = false;
                //设置未保存提示
                if (notSavedTips == false)
                {
                    this.Text += "*";
                    notSavedTips = true;
                }
            }
            else if (state == true)
            {
                isSaved = true;
                if (notSavedTips == true)
                {
                    this.Text = originallyFormName;
                    notSavedTips = false;
                }
            }
        }
        #endregion 系统生成函数区

        #region 菜单栏文件功能实现区函数
        /// <summary>
        /// 新建一个xml
        /// </summary>
        public void NewXml()
        {
            ClearXmlAllInfo();
            xmlFile = new XDocument(new XElement("Root"));
            LoadXmlToTree(xmlFile.Root, treeView_XMLTree.Nodes);

            WriteLog("已经新建了xml文件");
            timer_AutoBackUp.Start();
            isOpened = false;
            SetIsSaved(false);
        }
        /// <summary>
        /// 打开一个xml
        /// </summary>
        public void OpenXML()
        {
            openFileDialog_XML.InitialDirectory = configSystem.configFile.Root.Element("上次工作路径").Value;
            var result = openFileDialog_XML.ShowDialog();
            if (result == DialogResult.OK)
            {
                try
                {
                    ClearXmlAllInfo();

                    xmlFile = XDocument.Load(openFileDialog_XML.FileName);//catch这个可能加载的不是xml文件
                    WriteLog("已经打开xml文件：" + openFileDialog_XML.FileName);

                    FileInfo fileInfo = new FileInfo(openFileDialog_XML.FileName);
                    configSystem.configFile.Root.Element("上次工作路径").Value = fileInfo.DirectoryName;

                    filePath = fileInfo.DirectoryName;
                    fileFullName = fileInfo.FullName;
                    fileName = fileInfo.Name;

                    //timer_AutoBackUp.
                    timer_AutoBackUp.Start();

                    LoadXmlToTree(xmlFile.Root, treeView_XMLTree.Nodes);
                    isOpened = true;
                    SetIsSaved(true);
                }
                catch (System.Xml.XmlException exception)
                {
                    WriteLog("你打开的不是xml文件，或xml文件已损坏！" + exception.Message, LogState.Warning);
                }

            }
        }
        /// <summary>
        /// 保存xml
        /// </summary>
        public void SaveXML()
        {
            if (xmlFile != null)
            {
                if (isOpened == false)
                {
                    WriteLog("正在另存一个新建的xml");
                    SaveAsXML();
                }
                else
                {
                    FileStream fs = new FileStream(fileFullName, FileMode.Create);
                    xmlFile.Save(fs);
                    fs.Close();
                    WriteLog(fileFullName + "保存成功", LogState.Good);
                }
                SetIsSaved(true);
            }
            else
            {
                WriteLog("你不能保存一个不存在的xml文件", LogState.Warning);
            }
        }
        /// <summary>
        /// 另存为xml
        /// </summary>
        public void SaveAsXML()
        {
            if (xmlFile != null)
            {
                var result = saveFileDialog_XML.ShowDialog();
                if (result == DialogResult.OK)
                {
                    WriteLog("另存为一个新的xml文件");
                    if (isOpened == false) isOpened = true;

                    fileFullName = saveFileDialog_XML.FileName;
                    canDoNextStep = true;
                    SaveXML();
                }
                else
                {
                    canDoNextStep = false;
                }
            }
            else
            {
                WriteLog("你不能保存一个不存在的xml文件", LogState.Warning);
            }
        }
        /// <summary>
        /// 卸载xml
        /// </summary>
        public void UninstallXml()
        {
            ClearXmlAllInfo();
            WriteLog("已经卸载了xml文件");
            timer_AutoBackUp.Stop();
            isOpened = false;
            SetIsSaved(true);
        }
        public void ExitXml()
        {
            this.Close();
        }

        #endregion 菜单栏文件功能实现区函数
        /// <summary>
        /// 清理有关xml所有项目1.treeView树状图Clear，2.dataGrid表格Clear，3.nodeToXml字典new，4.xmlFile元素本身null
        /// </summary>
        private void ClearXmlAllInfo()
        {
            treeView_XMLTree.Nodes.Clear();
            dataGridView_XML.Columns.Clear();
            nodeToXml = new Dictionary<TreeNode, XElement>();
            xmlFile = null;
        }
        #region 菜单栏文件功能区
        private void NewXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (isSaved == true)
            {
                NewXml();
            }
            else
            {
                XMLNextStep(XmlDialogState.New);
            }
        }
        private void OpenXML_ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //打开一个xml文件
            if (isSaved == true)
            {
                OpenXML();
            }
            else
            {
                XMLNextStep(XmlDialogState.Open);
            }
        }
        private void SaveXML_ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveXML();
        }
        private void SaveAsXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveAsXML();
        }
        private void EditConfigFile_ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Form_Config().ShowDialog();
        }
        private void ResetToDefault_ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var result = MessageBox.Show("确定重设为默认配置？", "配置文件更改", MessageBoxButtons.YesNo);
            if (result == DialogResult.Yes)
            {
                configSystem.CreateDefaultConfig();
                WriteLog("已经重新生成配置文件", LogState.Good);
            }
        }
        private void UninstallXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (isSaved == true)
            {
                UninstallXml();
            }
            else
            {
                XMLNextStep(XmlDialogState.Uninstall);
            }
        }
        private void Exit_ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (isSaved == true)
            {
                ExitXml();
            }
            else
            {
                XMLNextStep(XmlDialogState.Exit);
            }
        }
        #endregion 菜单栏文件功能区

        #region 主功能事件区
        //映射treeView树状图中选中的元素到datagrid中
        private void treeView_XMLTree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            dataGridView_XML.Columns.Clear();
            //获取当前映射元素
            currentElement = nodeToXml[treeView_XMLTree.SelectedNode];
            //映射元素名字
            dataGridView_XML.Columns.Add("ElementName", "Name");
            dataGridView_XML.Rows[0].Cells[0].Value = currentElement.Name;
            //映射元素值
            dataGridView_XML.Columns.Add("ElementText", "Text");
            dataGridView_XML.Rows[0].Cells[1].Value = currentElement.Value;
            //映射元素属性
            if (currentElement.HasAttributes)
            {
                int count = 0;
                foreach (var a in currentElement.Attributes())
                {
                    dataGridView_XML.Columns.Add("AttributeName" + count, "AttributesName" + count);
                    dataGridView_XML.Rows[0].Cells[count * 2 + 2].Value = a.Name;
                    dataGridView_XML.Columns.Add("AttributeValue" + count.ToString(), "AttributesValue" + count.ToString());
                    dataGridView_XML.Rows[0].Cells[count * 2 + 3].Value = a.Value;
                    count++;
                }
            }
        }
        //更改xml主功能
        private void dataGridView_XML_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            int cIndex = e.ColumnIndex;
            //改元素名字
            if (cIndex == 0)
            {
                char temp = dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString()[0];
                //检查元素名称是否以数字开头
                if (temp > 47 && temp < 58)//48是0，57是9
                {
                    dataGridView_XML.Rows[0].Cells[cIndex].Value = dataCellBeginEditValue;
                    WriteLog("元素名不能以数字为开头", LogState.Warning);
                }
                //不是以数字开头
                else
                {
                    currentElement.Name = dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString();
                    treeView_XMLTree.SelectedNode.Text = currentElement.Name.ToString();
                }

            }
            //改元素值
            else if (cIndex == 1)
            {
                currentElement.Value = dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString();
            }
            else
            {
                //改元素属性名字
                if (cIndex % 2 == 0)
                {
                    char temp = dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString()[0];
                    //检查属性名是否以数字开头
                    if (temp > 47 && temp < 58)
                    {
                        dataGridView_XML.Rows[0].Cells[cIndex].Value = dataCellBeginEditValue;
                        WriteLog("属性名不能以数字为开头", LogState.Warning);
                    }
                    //不是以数字开头
                    else
                    {
                        int columnCount = dataGridView_XML.Columns.Count;
                        bool canEdit = true;
                        //>4是多属性的情况,需要检查修改后的名字和原来的属性名是否一样
                        if (columnCount > 4)
                        {
                            string cellValue = dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString();

                            for (int i = 2; i < columnCount; i += 2)
                            {
                                //跳过检查自身
                                if (cIndex == i) continue;
                                else
                                {
                                    if (dataGridView_XML.Rows[0].Cells[i].Value.ToString() == cellValue)
                                    {
                                        MessageBox.Show("属性名不能一样！属性名和第" + (i + 1) + "列一样！");
                                        //属性名字回滚
                                        dataGridView_XML.Rows[0].Cells[cIndex].Value = dataCellBeginEditValue;
                                        canEdit = false;
                                        break;
                                    }
                                }
                            }
                        }
                        //可以改属性名字
                        if (canEdit)
                        {
                            XElement myCompare = new XElement(currentElement);
                            currentElement.Attributes().Remove();
                            foreach (var a in myCompare.Attributes())
                            {
                                if (a.Name == dataCellBeginEditValue)
                                {
                                    currentElement.Add(new XAttribute(dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString(), dataGridView_XML.Rows[0].Cells[cIndex + 1].Value.ToString()));
                                }
                                else
                                {
                                    currentElement.Add(a);
                                }
                            }
                        }
                    }
                }
                else//改元素属性值
                {
                    currentElement.Attribute(dataGridView_XML.Rows[0].Cells[cIndex - 1].Value.ToString()).Value = dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString();
                }
            }
            //设置未保存状态
            if (dataGridView_XML.Rows[0].Cells[cIndex].Value.ToString() != dataCellBeginEditValue)
            {
                SetIsSaved(false);
            }
        }
        //收集编辑前的值，用来判断是否为没保存的文件
        private void dataGridView_XML_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            dataCellBeginEditValue = dataGridView_XML.Rows[0].Cells[e.ColumnIndex].Value.ToString();
        }
        #endregion 主功能事件区

        #region 工具栏按钮功能区
        private void toolStripButton_NewAttribute_Click(object sender, EventArgs e)
        {

            if (HaveSelectedNode())
            {
                XAttribute attribute;
                string attributeNameTemp = "NewAttributeName";
                if (currentElement.HasAttributes)
                {
                    while (currentElement.Attribute(attributeNameTemp) != null)
                    {
                        attributeNameTemp += "-1";
                    }

                }
                attribute = new XAttribute(attributeNameTemp, "Value");
                currentElement.Add(attribute);
                string temp = (currentElement.Attributes().Count() - 1).ToString();
                dataGridView_XML.Columns.Add("AttributeName" + temp, "AttributeName" + temp);
                dataGridView_XML.Rows[0].Cells[dataGridView_XML.Columns.Count - 1].Value = attribute.Name.ToString();
                dataGridView_XML.Columns.Add("AttributeValue" + temp, "AttributeValue" + temp);
                dataGridView_XML.Rows[0].Cells[dataGridView_XML.Columns.Count - 1].Value = attribute.Value;

                SetIsSaved(false);
            }

        }
        private void toolStripButton_DeleteAttribute_Click(object sender, EventArgs e)
        {
            if (dataGridView_XML.SelectedCells.Count != 0)
            {
                currentElement = nodeToXml[treeView_XMLTree.SelectedNode];

                List<int> selectIndex = new List<int>();
                bool canDelete = true;
                foreach (DataGridViewCell a in dataGridView_XML.SelectedCells)
                {
                    if (a.ColumnIndex < 2)
                    {
                        WriteLog("你不能删除元素名称或者文本", LogState.Warning);
                        canDelete = false;
                        break;
                    }
                    selectIndex.Add(a.ColumnIndex);
                }
                if (canDelete)
                {
                    selectIndex.Sort();
                    selectIndex.Reverse();
                    bool hasChooseOnValue = false;
                    int ValueChoiceNum = 0;
                    foreach (var a in selectIndex)
                    {
                        if (a % 2 == 0)//如果选中的是属性名字
                        {
                            if (hasChooseOnValue)
                            {
                                hasChooseOnValue = false;
                                if (a == ValueChoiceNum - 1)
                                {
                                    continue;
                                }
                            }
                            currentElement.Attribute(dataGridView_XML.Rows[0].Cells[a].Value.ToString()).Remove();
                            dataGridView_XML.Columns.Remove(dataGridView_XML.Columns[a + 1]);
                            dataGridView_XML.Columns.Remove(dataGridView_XML.Columns[a]);
                        }
                        if (a % 2 == 1)
                        {
                            hasChooseOnValue = true;
                            ValueChoiceNum = a;

                            currentElement.Attribute(dataGridView_XML.Rows[0].Cells[a - 1].Value.ToString()).Remove();
                            dataGridView_XML.Columns.Remove(dataGridView_XML.Columns[a]);
                            dataGridView_XML.Columns.Remove(dataGridView_XML.Columns[a - 1]);
                            continue;
                        }
                    }
                }
                SetIsSaved(false);
            }
            else
            {
                WriteLog("未选中任何单元格，无法删除属性", LogState.Warning);
            }
        }
        #endregion 工具栏按钮功能区
        private void NewElementIntoElement()
        {
            XElement element = new XElement("NewElement");
            currentElement = nodeToXml[treeView_XMLTree.SelectedNode];
            TreeNode node = new TreeNode(element.Name.ToString());
            treeView_XMLTree.SelectedNode.Nodes.Add(node);
            currentElement.Add(element);
            nodeToXml.Add(node, element);
        }
        private void toolStripButton_NewElement_Click(object sender, EventArgs e)
        {
            SetIsSaved(false);

            if (treeView_XMLTree.SelectedNode != null)
            {
                NewElementIntoElement();
            }
            else
            {
                if (xmlFile == null)
                {
                    xmlFile = new XDocument();
                }
                if (xmlFile.Root == null)
                {
                    XElement element = new XElement("NewElement");
                    xmlFile = new XDocument(element);
                    TreeNode node = new TreeNode(element.Name.ToString());
                    nodeToXml.Add(node, element);
                    treeView_XMLTree.Nodes.Add(node);
                }
                else
                {
                    treeView_XMLTree.SelectedNode = treeView_XMLTree.Nodes[0];
                    NewElementIntoElement();
                }
            }
        }
        private void DicNodesTraversalClear(Dictionary<TreeNode, XElement> dic, TreeNode node)
        {
            if (node.Nodes.Count == 0)
            {
                dic.Remove(node);
            }
            else
            {
                foreach (TreeNode a in node.Nodes)
                {
                    DicNodesTraversalClear(dic, a);
                }
            }
        }
        private void toolStripButton_DeleteElement_Click(object sender, EventArgs e)
        {
            if (HaveSelectedNode())
            {
                if (currentElement != xmlFile.Root)
                {
                    DicNodesTraversalClear(nodeToXml, treeView_XMLTree.SelectedNode);//遍历清除字典
                }
                else//如果是根元素，直接把字典给重新赋值
                {
                    nodeToXml = new Dictionary<TreeNode, XElement>();
                }
                currentElement.Remove();
                dataGridView_XML.Columns.Clear();
                treeView_XMLTree.SelectedNode.Remove();
                SetIsSaved(false);
            }
        }
        private void CopyElement(XElement originalElement, TreeNode originalNode)
        {
            XElement element = new XElement(originalElement.Name, originalElement.Value, originalElement.Attributes());
            //至关重要！如果直接new的话，会包含子集，造成空间浪费！
            TreeNode node = new TreeNode(element.Name.ToString());

            originalNode.Parent.Nodes.Add(node);
            originalElement.Parent.Add(element);

            nodeToXml.Add(node, element);
            treeView_XMLTree.SelectedNode = node;

        }
        private void toolStripButton_CopyElement_Click(object sender, EventArgs e)
        {
            if (HaveSelectedNode())
            {
                if (currentElement != xmlFile.Root)
                {
                    CopyElement(currentElement, treeView_XMLTree.SelectedNode);
                    SetIsSaved(false);
                }
                else
                {
                    WriteLog("你选择的是根元素，无法复制创建", LogState.Warning);
                }
            }
        }
        private bool HaveSelectedNode()
        {
            if (treeView_XMLTree.SelectedNode != null)
            {
                currentElement = nodeToXml[treeView_XMLTree.SelectedNode];
                return true;
            }
            else
            {
                WriteLog("未选择任何节点", LogState.Warning);
                return false;
            }
        }
        private void CopyElementIncludeChindren(XElement x, TreeNodeCollection nodes)
        {
            LoadXmlToTree(x, nodes);
        }
        private void toolStripButton_CopyElementIncludeChildren_Click(object sender, EventArgs e)
        {
            if (HaveSelectedNode())
            {
                if (currentElement != xmlFile.Root)
                {
                    XElement element = new XElement(currentElement);
                    xmlFile.Root.Add(element);
                    CopyElementIncludeChindren(element, treeView_XMLTree.SelectedNode.Parent.Nodes);
                    SetIsSaved(false);
                }
                else
                {
                    WriteLog("你选择的是根元素，无法复制创建", LogState.Warning);
                }
            }
        }
    }

}
